#include "monitor/monitor.h"
#include "cpu/helper.h"
#include <setjmp.h>
#include "monitor/watchpoint.h"
/* The assembly code of instructions executed is only output to the screen
 * when the number of instructions executed is less than this value.
 * This is useful when you use the `si' command.
 * You can modify this value as you want.
 */
#define MAX_INSTR_TO_PRINT 10

int nemu_state = STOP;

int exec(swaddr_t);

char assembly[80];
char asm_buf[128];

/* Used with exception handling. */
jmp_buf jbuf;

void print_bin_instr(swaddr_t eip, int len) {
	int i;
	int l = sprintf(asm_buf, "%8x:   ", eip);
	for(i = 0; i < len; i ++) {
		l += sprintf(asm_buf + l, "%02x ", instr_fetch(eip + i, 1));
	}
	sprintf(asm_buf + l, "%*.s", 50 - (12 + 3 * len), "");
}

/* This function will be called when an `int3' instruction is being executed. */
void do_int3() {
	printf("\nHit breakpoint at eip = 0x%08x\n", cpu.eip);
	nemu_state = STOP;
}

/* Simulate how the CPU works. */
void cpu_exec(volatile uint32_t n) {//这个函数的参数是n，代表要执行的次数。其中volatile是易失的意思，在这里表示不要优化读取
	if(nemu_state == END) {
		printf("Program execution has ended. To restart the program, exit NEMU and run again.\n");
		return;
	}//首先检查一下state状态变量，如果已经结束，那么不允许再次执行，也就是说执行结束了，循环会多一次在return
	nemu_state = RUNNING;//表示模拟器开始执行指令

#ifdef DEBUG//预处理指令来包含调试代码，允许编译时通过DEBUG宏来调试输出
	volatile uint32_t n_temp = n;//用这个是避免编译的时候声明出现冲突，用n_temp来存储n的实际值，n的原始值不会改变
#endif

	setjmp(jbuf);//设置一个跳转缓冲区，以便在特定条件下，遇到陷阱或中断，能够跳转回这里。可能用于处理异常或中断

	for(; n > 0; n --) {//如果n是-1，要转变成无符号整形就是232-1这么多次循环。
    /*循环执行指令，直到达到用户输入的n次，或者？执行到hit good trap宏*/
#ifdef DEBUG//是否要输出调试信息
		swaddr_t eip_temp = cpu.eip;
		if((n & 0xffff) == 0) {
			/* Output some dots while executing the program. */
			fputc('.', stderr);
		}
#endif

		/* Execute one instruction, including instruction fetch,
		 * instruction decode, and the actual execution. */
		int instr_len = exec(cpu.eip);//exec()是让CPU执行一条指令，这个函数的返回值可能是执行指令所需要的字节数，指令的长度

		cpu.eip += instr_len;//让eip指向下一条指令，相加在一起就是下一条指令的地址

#ifdef DEBUG
		print_bin_instr(eip_temp, instr_len);
		strcat(asm_buf, assembly);
		Log_write("%s\n", asm_buf);
		if(n_temp < MAX_INSTR_TO_PRINT) {
			printf("%s\n", asm_buf);
		}
#endif

		/* TODO: check watchpoints here. */
        WP *p = check();
        if(p != NULL)
        {
            printf("Hint watchpoint %d at address 0x%08x,expr = %s\n",p->NO,cpu.eip-instr_len,p->expr);
            printf("old value = 0x%08x\n new_value = 0x%08x\n ",p->old_value,p->new_value);
            p->old_value = p->new_value;
            return ;
        }

#ifdef HAS_DEVICE
		extern void device_update();
		device_update();
#endif

		if(nemu_state != RUNNING) { return; }
	}

	if(nemu_state == RUNNING) { nemu_state = STOP; }//直接让NEMU_state变成stop，就是程序正常执行完，就stop停下
}
